'''
Created on Apr 6, 2011

Models for SHARE content

@author: glow
'''

from google.appengine.ext import db
from google.appengine.ext.db import polymodel
from google.appengine.api import users

from django.conf import settings

import controlledterminology.models as ct_models

class Context(db.Model):
  """
  eg CDISC SDTM
  """
  name = db.StringProperty('Name', required=True)
  label = db.StringProperty('Label')
  description = db.StringProperty('Description', required=True)

class CollectionType(db.Model): 
  """
  Signifies levels within model in abstract fashion
  so using CDISC SDTM as an example:
  Observation Class = 0
  Domain = 1 
  Concept = 2
  can use to rank things
  """ 
  level = db.IntegerProperty('Level', required=True)
  name = db.StringProperty('Name', required=True)
  description = db.StringProperty('Description')
  timestamp = db.DateTimeProperty('Time stamp', auto_now=True)
  

  
class Collection(polymodel.PolyModel):
  """
  Collection Definition
  """
  context = db.ReferenceProperty(Context, required=True)
  collection_type = db.ReferenceProperty(CollectionType, required=True)
  name = db.StringProperty('Name')
  timestamp = db.DateTimeProperty('Time stamp', auto_now=True)
    
  @property
  def is_complete(self):
    return False in [x.is_set() for x in self.item_children]

class CollectionAttributeTemplate(db.Model):  
  """
  Definition of Attribute - Normalised
  """
  name = db.StringProperty('Name', required=True)
  label = db.StringProperty('Label')
  definition = db.StringProperty('Definition')
  help = db.StringProperty('Help')
  rank = db.IntegerProperty('Rank', required=False)

  
class CollectionAttribute(db.Model):
  """
  Realization of an Attribute
  """
  # Collection
  collection = db.ReferenceProperty(Collection, collection_name='attributes')
  # attribute definition
  attribute = db.ReferenceProperty(CollectionAttributeTemplate, 'Attribute')
  # value
  value = db.StringProperty('Value')
  # user
  user = db.UserProperty('User')

  # audit trail
  timestamp = db.DateTimeProperty('Time stamp', 
                                  auto_now=True)
  user = db.UserProperty('User')
  # TODO: Auditing of element
  # history of values set
  #history_value = db.StringListProperty('Values')
  # history of users setting values
  #history_user = db.ListProperty(users.User, 'Users')
  # history of values by time stamp
  #history_stamp = db.StringListProperty('Time stamps')
  
  def __cmp__(self, other):
    """
    Sort on the attribute rank, put unranked to the bottom
    """
    if not self.attribute.rank:
      return 1
    elif not other.attribute.rank:
      return -1
    else:
      return cmp(self.attribute.rank, other.attribute.rank)
    
class Variable(polymodel.PolyModel):
  """"
  a Row in the content template spreadsheet
  """
  # Ordering
  rank = db.IntegerProperty('Rank', required=True)
  # Name for the Variable
  name = db.StringProperty('Name', required=True)
  # Label for the Variable
  label = db.StringProperty('Label', required=True)
  # Definition of the Variable
  definition = db.StringProperty('Share Generic Definition')
  # completion guidelines
  guidelines = db.StringProperty('Completion Guidelines') 

  def put(self):
    if not self.rank:
      self.rank = CollectionType.all().count() + 1
    return db.Model.put(self)
  

class Attribute(polymodel.PolyModel):
  """
  Column in the content template spreadsheet
  """
  # Ordering
  rank = db.IntegerProperty('Rank')
  # Name for the Variable
  name = db.StringProperty('Name', required=True)
  # Label for the Variable
  label = db.StringProperty('Label')
  # Definition for the Variable
  definition = db.StringProperty('Definition of Attribute')
  # completion guidelines
  guidelines = db.StringProperty('Completion Guidelines') 
  
class DependentAttribute(Attribute):
  """
  Attribute that depends on value of other
  attribute so should be limited
  """
  references = db.ReferenceProperty(Attribute)
  dependancy_type = db.StringProperty('Link')

class ReferencedAttribute(Attribute):
  """
  Attribute that should have a picklist
  """
  # this is a reference to the CodedTerminology
  reference_to = db.ReferenceProperty(ct_models.CodedTerminology)
  
  
class Template(Collection):
  """
  Something intended to have children which will
  inherit from this instance 
  - have a parent collection
  """  
  pass

class Template_Variable(Variable):
  """
  Something intended to have children which will
  inherit from this instance 
  - have a template
  """  
  # Reference to the variable
  template = db.ReferenceProperty(Template)
  # Reference to the Variable 
  variable = db.ReferenceProperty(Variable)
  # Inherit the values and attributes for the variable   
  inherit = db.BooleanProperty('Inherit', default=False)
    
#class Template_Attribute(db.Model):
#  """
#  Attribute for a template
#  """
#  template = db.ReferenceProperty('Template')
#  attribute = db.ReferenceProperty('Attribute')

class Concept(Collection):
  """
  Specialised type of Collection 
  
  """
  pass

class UserRole(db.Model):
  name = db.StringProperty()
  
class UserPrefs(db.Model):
  user = db.UserProperty()
  role = db.ReferenceProperty(UserRole)
  
class Instance(db.Model):
  """
  Instance is an actual key/value record
  """
  # Collection reference 
  collection = db.ReferenceProperty(Collection, 
                                    collection_name='instances')
  # reference to the variable  
  variable = db.ReferenceProperty(Variable, 
                                  'Row', 
                                  required=True)
  # reference to the variable  
  attribute = db.ReferenceProperty(Attribute, 
                                   'Column', 
                                   required=True)
  value = db.StringProperty('Value', 
                            required=True, 
                            default="")
  user = db.UserProperty('User')
  date_stamp_created = db.DateTimeProperty('Date stamp', 
                                           auto_now_add=True)
  save_date = db.DateTimeProperty('Date stamp', 
                                   auto_now=True)
  # history of values set
  history_value = db.StringListProperty(default=None)
  # history of users setting values
  history_user = db.ListProperty(users.User)
  # history of values by time stamp
  history_stamp = db.StringListProperty()
  
  @property
  def is_set(self):
    # define whether an item has been set
    return self.date_stamp_created == self.save_date
  
  
  def __cmp__(self, other):
    if self.variable.rank == other.variable.rank:
      return cmp(self.attribute.rank, other.attribute.rank)
    else:
      return cmp(self.variable.rank, other.variable.rank)
  
  